<?php
if(!interface_exists('XQuery', false)){
	require(XFRAMEWORK_DIR.'/module/orm/XQuery.php');
}
class XARQuery implements XQuery{
	protected $dao = null;
	protected $table = null;
	protected $criteria = null; 
	
	public function __construct($modelName){
		if(!XClassLoader::loader($modelName)->isSubclassOf('XARRecord')){
			throw new XORMException("class {$modelName} is not a sub class of XARRecord");
		}
		$this->dao = XARDAO::dao($modelName);
	}
	
	/**
	 * @return XARQuery
	 */		
	public static function get($modelName){
		return new self($modelName);
	}
	
	/**
	 * @return XARQuery
	 */	
	public function setDao(XDAO $dao){
		$this->dao = $dao;
		return $this;
	}
	
	/**
	 * @return XARDAO
	 */	
	public function dao(){
		return $this->dao;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function setCriteria(XCriteria $criteria){
		$this->criteria = $criteria;
		return $this;
	}
	
	/**
	 * @return XCriteria
	 */
	public function criteria(){
		if(!$this->criteria){			
			$this->criteria = new XCriteria();
		}
		return $this->criteria;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function PK($pk){
		$this->criteria()->eq($this->dao()->table()->PK(), $pk);
		return $this;
	}

	/**
	 * @return XARQuery
	 */	
	public function uniqueId($uniqueId){
		return $this->PK($uniqueId);
	}
	
	/**
	 * @return XARQuery
	 */
	public function example(XModel $example){
		$this->criteria()->example($example);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */
	public function regexp($key, $value){
		$this->criteria()->regexp($key, addslashes($value));
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */
	public function result($result){
		$this->criteria()->result(addslashes($result));
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */
	public function eq($key, $value){
		if(is_array($value)){
			return $this->in($key, $value);
		}
		if(is_null($value)){
			return $this->isNull($key);
		}
		$this->criteria()->eq($key, addslashes($value));
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function not($key, $value){
		if(is_array($value)){
			return $this->notIn($key, $value);
		}
		if(is_null($value)){
			return $this->notNull($key);
		}		
		$this->criteria()->not($key, addslashes($value));
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function in($key, array $array){
		if(count($array) == 0){
			return $this->isNull($key);
		}
		$this->criteria()->in($key, $array);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function notIn($key, array $array){
		if(count($array) == 0){
			return $this->isNull($key);
		}
		$this->criteria()->notIn($key, $array);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function isNull($key){
		$this->criteria()->isNull($key);
		return $this;
	}	
	
	/**
	 * @return XARQuery
	 */	
	public function notNull($key){
		$this->criteria()->notNull($key);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function like($key, $value, $mode = LIKE_ANYWHERE){
		$this->criteria()->like($key, addslashes($value), $mode);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */
	public function between($key, $from, $to){
		$this->criteria()->between($key, addslashes($from), addslashes($to));
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function offset($offset){
		$this->criteria()->offset($offset);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function size($size){
		$this->criteria()->size($size);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function limit($size){
		$this->criteria()->limit($size);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function orderBy($field, $asc = true){
		$this->criteria()->orderBy($field, $asc);
		return $this;
	}
	
	/**
	 * @return XARQuery
	 */	
	public function asc($field){
		return $this->orderBy($field, true);
	}
	
	/**
	 * @return XARQuery
	 */	
	public function desc($field){
		return $this->orderBy($field, false);
	}
			
	/**
	 * @return XModel
	 */	
	public function find($PK = null, $asArray = false){
		if(!is_null($PK)){
			$table = $this->dao()->table();
			$this->eq($table->PK(), $PK);
		}
		$this->offset(0);
		$this->size(1);
		return $this->dao()->find($this->criteria(), $asArray);
	}
	
	/**
	 * @return array
	 */
	public function findAll($asArray = false){
		return $this->dao()->findAll($this->criteria(), $asArray);	
	}
	
	/**
	 * @return XARQuery
	 */		
	public function table($table){
		if(is_object($table) && $table instanceof XTable){
			$this->table = $table->name();
			return $this;
		}
		$this->table = $table;
		return $this;
	}
	
	/**
	 * @return int
	 */		
	public function count($field = null){
		if(!is_null($field)){
			$field = addslashes($field);
		}
		$result = $this->dao()->queryCriteria($this->criteria()->count($field));
		return $this->aggregateResult($result, false);
	}
	
	/**
	 * @return int
	 */		
	public function sum($field){
		$result = $this->dao()->queryCriteria($this->criteria()->sum(addslashes($field)));
		return $this->aggregateResult($result);
	}
	
	/**
	 * @return int
	 */		
	public function avg($field){
		$result = $this->dao()->queryCriteria($this->criteria()->avg(addslashes($field)));
		return $this->aggregateResult($result);
	}
	
	/**
	 * @return int
	 */		
	public function max($field){
		$result = $this->dao()->queryCriteria($this->criteria()->max(addslashes($field)));
		return $this->aggregateResult($result);
	}	
	
	/**
	 * @return int
	 */		
	public function min($field){
		$result = $this->dao()->queryCriteria($this->criteria()->min(addslashes($field)));
		return $this->aggregateResult($result);
	}	
	
	protected function aggregateResult($result, $float = true){
		if(!is_array($result)){
			return $result;
		}
		do{
			$key = array_keys($result);
			$key = array_shift($key);
			$result = array_values($result[$key]);			
		}while(is_array($result) && is_array($result[$key]));
		if($float){			
			return floatval($result[$key]);		
		}
		return intval($result[$key]);
	}
	
	/**
	 * @return XARQuery
	 */	
	public function cloneQuery(){
		return clone $this;
	}	
}
?>